﻿using System.Security.Cryptography;
using System.Text;

namespace Tools.Encryption
{
    public static class Security
    {

        #region AES 加密解密

        /// <summary>
        /// 使用 AES 对称算法加密字符串
        /// </summary>
        public static string EncryptAES(string plainText, byte[] key, byte[] iv)
        {
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = key;
                aesAlg.IV = iv;

                using (ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
                using (MemoryStream ms = new MemoryStream())
                using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                using (StreamWriter sw = new StreamWriter(cs))
                {
                    sw.Write(plainText);
                    sw.Flush();    // 先刷新写入流，确保数据写入CryptoStream
                    cs.FlushFinalBlock();  // 再刷写CryptoStream
                    return Convert.ToBase64String(ms.ToArray());
                }
            }
        }

        /// <summary>
        /// 使用 AES 对称算法解密字符串
        /// </summary>
        public static string DecryptAES(string cipherText, byte[] key, byte[] iv)
        {
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = key;
                aesAlg.IV = iv;

                using (ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
                using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(cipherText)))
                using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                using (StreamReader sr = new StreamReader(cs))
                {
                    return sr.ReadToEnd();
                }
            }
        }

        #endregion

        #region SHA256 哈希

        /// <summary>
        /// 使用 SHA256 算法生成字符串的哈希值
        /// </summary>
        public static string ComputeSHA256(string input)
        {
            using (SHA256 sha256 = SHA256.Create())
            {
                byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(input));
                return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
            }
        }

        #endregion

        #region HMACSHA256

        /// <summary>
        /// 使用 HMACSHA256 算法生成哈希
        /// </summary>
        public static string ComputeHMACSHA256(string input, string key)
        {
            using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
            {
                byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(input));
                return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
            }
        }

        #endregion

        #region md5加密
        /// <summary>
        /// 计算 MD5 哈希值
        /// </summary>
        /// <param name="input">待加密字符串</param>
        /// <param name="length">长度，16 或 32</param>
        /// <param name="toUpper">是否转为大写</param>
        /// <returns>MD5 加密结果</returns>
        public static string ComputeMD5(string input, int length = 32, bool toUpper = false)
        {
            using var md5 = MD5.Create();
            byte[] bytes = Encoding.UTF8.GetBytes(input);
            byte[] hash = md5.ComputeHash(bytes);

            string result = BitConverter.ToString(hash).Replace("-", "");

            if (length == 16)
                result = result.Substring(8, 16); // 截取中间16位

            return toUpper ? result.ToUpper() : result.ToLower();
        }
        #endregion


        #region 字符串对称加密 AES

        public static string EncryptAES(string plainText, string key, string iv)
        {
            using Aes aes = Aes.Create();
            aes.Key = Encoding.UTF8.GetBytes(key);
            aes.IV = Encoding.UTF8.GetBytes(iv);

            using MemoryStream ms = new();
            using CryptoStream cs = new(ms, aes.CreateEncryptor(), CryptoStreamMode.Write);
            using StreamWriter sw = new(cs);
            sw.Write(plainText);
            sw.Close();
            return Convert.ToBase64String(ms.ToArray());
        }

        public static string DecryptAES(string cipherText, string key, string iv)
        {
            using Aes aes = Aes.Create();
            aes.Key = Encoding.UTF8.GetBytes(key);
            aes.IV = Encoding.UTF8.GetBytes(iv);

            using MemoryStream ms = new(Convert.FromBase64String(cipherText));
            using CryptoStream cs = new(ms, aes.CreateDecryptor(), CryptoStreamMode.Read);
            using StreamReader sr = new(cs);
            return sr.ReadToEnd();
        }

        #endregion




        #region RSA 密钥对

        /// <summary>
        /// 生成 RSA 密钥对（PEM 格式）
        /// </summary>
        /// <param name="keySize">密钥长度，默认为 2048</param>
        /// <returns>返回包含公钥和私钥的元组（PEM 格式）</returns>
        public static (string PublicKey, string PrivateKey) GenerateKeyPair(int keySize = 2048)
        {
            using RSA rsa = RSA.Create(keySize);
            var publicKey = ExportPublicKeyPem(rsa);
            var privateKey = ExportPrivateKeyPem(rsa);
            return (publicKey, privateKey);
        }

        /// <summary>
        /// 使用公钥加密明文
        /// </summary>
        /// <param name="plainText">要加密的明文</param>
        /// <param name="publicKeyPem">PEM 格式的公钥</param>
        /// <returns>Base64 编码的密文</returns>
        public static string EncryptByPublic(string plainText, string publicKeyPem)
        {
            using RSA rsa = RSA.Create();
            rsa.ImportFromPem(publicKeyPem);
            var data = Encoding.UTF8.GetBytes(plainText);
            var encrypted = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1); // 使用 PKCS1 填充（兼容性强）
            return Convert.ToBase64String(encrypted);
        }

        /// <summary>
        /// 使用私钥解密密文
        /// </summary>
        /// <param name="cipherTextBase64">Base64 编码的密文</param>
        /// <param name="privateKeyPem">PEM 格式的私钥</param>
        /// <returns>解密后的明文</returns>
        public static string DecryptByPrivate(string cipherTextBase64, string privateKeyPem)
        {
            using RSA rsa = RSA.Create();
            rsa.ImportFromPem(privateKeyPem);
            var data = Convert.FromBase64String(cipherTextBase64);
            var decrypted = rsa.Decrypt(data, RSAEncryptionPadding.Pkcs1);
            return Encoding.UTF8.GetString(decrypted);
        }

        /// <summary>
        /// 使用私钥对数据进行签名（实现“加密”功能）
        /// </summary>
        /// <param name="plainText">要签名的原始数据</param>
        /// <param name="privateKeyPem">PEM 格式的私钥</param>
        /// <returns>签名字符串（Base64 编码）</returns>
        public static string EncryptByPrivate(string plainText, string privateKeyPem)
        {
            using RSA rsa = RSA.Create();
            rsa.ImportFromPem(privateKeyPem);
            var data = Encoding.UTF8.GetBytes(plainText);
            var signed = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // 私钥签名
            return Convert.ToBase64String(signed);
        }

        /// <summary>
        /// 使用公钥验证签名是否合法
        /// </summary>
        /// <param name="plainText">原始数据</param>
        /// <param name="signatureBase64">签名字符串（Base64 编码）</param>
        /// <param name="publicKeyPem">PEM 格式的公钥</param>
        /// <returns>如果签名有效返回 true，否则返回 false</returns>
        public static bool VerifySignature(string plainText, string signatureBase64, string publicKeyPem)
        {
            using RSA rsa = RSA.Create();
            rsa.ImportFromPem(publicKeyPem);
            var data = Encoding.UTF8.GetBytes(plainText);
            var signature = Convert.FromBase64String(signatureBase64);
            return rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // 公钥验签
        }

        /// <summary>  
        /// 将 RSA 公钥导出为 PEM 格式字符串  
        /// </summary>  
        /// <param name="rsa">RSA 实例</param>  
        /// <returns>PEM 格式的公钥</returns>  
        private static string ExportPublicKeyPem(RSA rsa)
        {
            var publicKey = rsa.ExportSubjectPublicKeyInfo();
            var pem = PemEncoding.Write("PUBLIC KEY", publicKey);
            return pem != null ? new string(pem) : string.Empty; // 确保返回非 null 值  
        }

        /// <summary>  
        /// 将 RSA 私钥导出为 PEM 格式字符串  
        /// </summary>  
        /// <param name="rsa">RSA 实例</param>  
        /// <returns>PEM 格式的私钥</returns>  
        private static string ExportPrivateKeyPem(RSA rsa)
        {
            var privateKey = rsa.ExportPkcs8PrivateKey();
            var pem = PemEncoding.Write("PRIVATE KEY", privateKey);
            return pem != null ? new string(pem) : string.Empty; // 确保返回非 null 值  
        }

        #endregion
    }
}



